﻿/// <summary>
/// FileName: ExpressionManager.cs
/// Author: Jiang Xiaolong
/// Created Time: 2015.05.14
/// Version: 1.0
/// Company: Sunnytech
/// Function: 变量和表达式管理，每个表达式和变量都对应一个特有的ID，可以用此ID获取变量和表达式的值；
///
/// Changed By:
/// Modification Time:
/// Discription:
/// </summary>

using System;
using System.Collections.Generic;
using Expression.api;

namespace Expression.impl
{
	public class ExpressionManager
	{
		//变量作用域
		private static Scope _scope;
		//公式类型变量，引用了其他变量
		private static Dictionary<string, ExpressionTree> _expressionVariable;
		/// <summary>
		/// 当前公式解析错误列表；
		/// </summary>
		public static List<ParseError> Errors = new List<ParseError>();
		//用于索引该变量会影响哪些公式；
		private static Dictionary<string, List<string>> _varToExp;
		//用于在公式更新时，改变变量公式索引
		private static Dictionary<string, List<string>> _expToVar;

		static ExpressionManager()
		{
			_scope = Scope.Create();
			_expressionVariable = new Dictionary<string, ExpressionTree>();
			_varToExp = new Dictionary<string, List<string>>();
			_expToVar = new Dictionary<string, List<string>>();
		}

		/// <summary>
		/// 创建变量；
		/// </summary>
		/// <param name="name_id">变量名；</param>
		/// <param name="type">变量类型，系统字符串形式；</param>
		/// <param name="value">变量值；</param>
		/// <returns>是否创建成功；</returns>
		public static bool CreateVariable(string name_id, Type type, object value)
		{
			Errors.Clear();
			if (IsCreated(name_id))
			{
				Errors.Add(ParseError.Error(new NameLocation(name_id), "变量：" + name_id + "，类型：" + type + "，该变量已创建，请勿重复创建！"));
				return false;
			}
			_scope.SetVariable(name_id, type, value);
			return true;
		}

		/// <summary>
		/// 创建变量；
		/// </summary>
		/// <param name="name_id">变量名；</param>
		/// <param name="type">变量类型，字符串形式；</param>
		/// <param name="value">变量值；</param>
		/// <returns>是否创建成功；</returns>
		public static bool CreateVariable(string name_id, string type, object value)
		{
			Errors.Clear();
			Type sysType = GetVariableType(type);
			if (sysType == null)
			{
				Errors.Add(ParseError.Error(new NameLocation(name_id), "变量：" + name_id + "，类型：" + type + "，该类型不存在！"));
				return false;
			}
			return CreateVariable(name_id, sysType, value);
		}

		/// <summary>
		/// 根据传入字符串返回类型；
		/// </summary>
		/// <param name="type">传入字符串类型；</param>
		/// <returns>返回系统类型；</returns>
		private static Type GetVariableType(string type)
		{
			if (type.Trim().ToLower() == "string")
			{
				return typeof(string);
			}
			else if (type.Trim().ToLower() == "float")
			{
				return typeof(float);
			}
			else if (type.Trim().ToLower() == "double")
			{
				return typeof(double);
			}
			else if (type.Trim().ToLower() == "bool")
			{
				return typeof(bool);
			}
			else if (type.Trim().ToLower() == "int")
			{
				return typeof(int);
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// 创建表达式；
		/// </summary>
		/// <param name="name_id">表达式名；</param>
		/// <param name="expression_str">表达式字符串；</param>
		/// <returns>是否创建成功；</returns>
		public static bool CreateExpression(string name_id, string expression_str)
		{
			Errors.Clear();
			if (IsCreated(name_id))
			{
				Errors.Add(ParseError.Error(new NameLocation(name_id), "表达式名：" + name_id + "，表达式：" + expression_str + "，该表达式已定义，请勿重复定义！"));
				return false;
			}
			ExpressionTree exp = ExpressionParsing.Parsing(name_id, expression_str, _scope);
			if (ExpressionParsing.Errors.Count > 0)
			{
				Errors.AddRange(ExpressionParsing.Errors);
				return false;
			}
			_expressionVariable.Add(name_id, exp);
			return true;
		}

		/// <summary>
		/// 该名字是否已创建变量或表达式；
		/// </summary>
		/// <param name="name_id">名字ID；</param>
		/// <returns>该名字是否已创建变量或表达式；</returns>
		public static bool IsCreated(string name_id)
		{
			if (_scope.IsCreated(name_id))
			{
				return true;
			}
			if (_expressionVariable.ContainsKey(name_id))
			{
				return true;
			}
			return false;
		}

		/// <summary>
		/// 该名字是否已创建变量；
		/// </summary>
		/// <param name="name_id">名字ID；</param>
		/// <returns>该名字是否已创建变量；</returns>
		public static bool IsCreatedVariable(string name_id)
		{
			if (_scope.IsCreated(name_id))
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		/// <summary>
		/// 该名字是否已创建表达式；
		/// </summary>
		/// <param name="name_id">名字ID；</param>
		/// <returns>该名字是否已创建表达式；</returns>
		public static bool IsCreatedExpression(string name_id)
		{
			if (_expressionVariable.ContainsKey(name_id))
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		/// <summary>
		/// 返回该名字对应的表达式或变量值；
		/// </summary>
		/// <param name="name_id">名字ID；</param>
		/// <returns>返回该名字对应的表达式或变量值；</returns>
		public static object GetValue(string name_id)
		{
			if (IsCreated(name_id))
			{
				if (IsCreatedVariable(name_id))
				{
					return _scope.Find(name_id).GetValue();
				}
				else
				{
					return _expressionVariable[name_id].Evaluate();
				}
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// 返回该名字对应的表达式或变量返回值类型；
		/// </summary>
		/// <param name="name_id">名字ID；</param>
		/// <returns>返回该名字对应的表达式或变量返回值类型；</returns>
		public static Type GetCurrentType(string name_id)
		{
			if (IsCreated(name_id))
			{
				if (IsCreatedVariable(name_id))
				{
					return _scope.Find(name_id).ExpType;
				}
				else
				{
					return _expressionVariable[name_id].ExpType;
				}
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// 根据表达式名返回表达式；
		/// </summary>
		/// <param name="name_id">表达式名；</param>
		/// <returns>表达式；</returns>
		public static ExpressionTree GetExpression(string name_id)
		{
			if (_expressionVariable.ContainsKey(name_id))
			{
				return _expressionVariable[name_id];
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// 根据变量名返回变量；
		/// </summary>
		/// <param name="name_id">变量名；</param>
		/// <returns>变量；</returns>
		public static Variable GetVariable(string name_id)
		{
			if (IsCreatedVariable(name_id))
			{
				return _scope.Find(name_id);
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// 改变某个变量的值； TODO：一个变量值改变，如何得知哪些公式也需要更新；
		/// </summary>
		/// <param name="name_id">变量名；</param>
		/// <param name="value">改变的值；</param>
		/// <returns>是否改变成功；</returns>
		public static bool ChangeValue(string name_id, object value)
		{
			Errors.Clear();
			if (IsCreatedVariable(name_id))
			{
				_scope.SetValue(name_id, value);
				return true;
			}
			else
			{
				Errors.Add(ParseError.Error(new NameLocation(name_id), "变量名：" + name_id + "，该变量未定义，不能赋值！"));
				return false;
			}
		}

		/// <summary>
		/// 改变某个公式变量对应的公式； TODO：一个变量值改变，如何得知哪些公式也需要更新；
		/// </summary>
		/// <param name="name_id">公式名；</param>
		/// <param name="expression_str">改变的公式；</param>
		/// <returns>是否改变成功；</returns>
		public static bool ChangeExpression(string name_id, string expression_str)
		{
			Errors.Clear();
			if (IsCreatedExpression(name_id))
			{
				DeleteVarExpRelation(name_id);
				ExpressionTree exp = ExpressionParsing.Parsing(name_id, expression_str, _scope);
				if (ExpressionParsing.Errors.Count > 0)
				{
					Errors.AddRange(ExpressionParsing.Errors);
					return false;
				}
				_expressionVariable[name_id] = exp;
				return true;
			}
			else
			{
				Errors.Add(ParseError.Error(new NameLocation(name_id), "公式名：" + name_id + "，该公式未定义，不能改变公式！"));
				return false;
			}
		}

		/// <summary>
		/// 解析公式时，记录当前公式涉及的变量；
		/// </summary>
		/// <param name="exp_name">公式名；</param>
		/// <param name="var_name">变量名；</param>
		public static void VarExpRelation(string exp_name, string var_name)
		{
			if (_varToExp.ContainsKey(var_name))
			{
				_varToExp[var_name].Add(exp_name);
			}
			else
			{
				_varToExp.Add(var_name, new List<string>() { exp_name });
			}
			if (_expToVar.ContainsKey(exp_name))
			{
				_expToVar[exp_name].Add(var_name);
			}
			else
			{
				_expToVar.Add(exp_name, new List<string>() { var_name });
			}
		}

		/// <summary>
		/// 公式改变时，删除原来公式与变量之间的关系；
		/// </summary>
		/// <param name="exp_name">公式名；</param>
		private static void DeleteVarExpRelation(string exp_name)
		{
			if (_expToVar.ContainsKey(exp_name))
			{
				for (int i = 0; i < _expToVar[exp_name].Count; i++)
				{
					if (_varToExp[_expToVar[exp_name][i]].Contains(exp_name))
					{
						_varToExp[_expToVar[exp_name][i]].Remove(exp_name);
					}
				}
				_expToVar[exp_name].Clear();
			}
		}

		/// <summary>
		/// 获取当变量或者公式改变时，受影响的公式列表；
		/// </summary>
		/// <param name="name_id">变量名或者公式名；</param>
		/// <returns>受影响公式列表；</returns>
		public static List<string> AssociatedExpression(string name_id)
		{ 
			if(_varToExp.ContainsKey(name_id))
			{
				List<string> associatedExp = new List<string>();
				AssociatedExpRecursion(associatedExp, name_id);
				return associatedExp;
			}
			else
			{
				return new List<string>();
			}
		}

		/// <summary>
		/// 递归调用，获取受影响公式列表；
		/// </summary>
		/// <param name="associated_exp"></param>
		/// <param name="name_id"></param>
		private static void AssociatedExpRecursion(List<string> associated_exp, string name_id)
		{
			for (int i = 0; i < _varToExp[name_id].Count; i++)
			{
				if (!associated_exp.Contains(_varToExp[name_id][i]))
				{
					associated_exp.Add(_varToExp[name_id][i]);
				}
				if (_varToExp.ContainsKey(_varToExp[name_id][i]))
				{
					AssociatedExpRecursion(associated_exp, _varToExp[name_id][i]);
				}
			}
		}

		/// <summary>
		/// 获取当前公式所涉及到的变量和公式名；
		/// </summary>
		/// <param name="name_id">公式名；</param>
		/// <returns>受影响公式和变量列表；</returns>
		public static List<string> AssociatedSubVariable(string name_id)
		{
			if (IsCreatedExpression(name_id))
			{
				if (_expToVar.ContainsKey(name_id))
				{
					List<string> associatedSubVar = new List<string>();
					AssociatedSubVarRecursion(associatedSubVar, name_id);
					return associatedSubVar;
				}
			}
			return new List<string>();
		}

		/// <summary>
		/// 递归调用，获取受影响公式列表；
		/// </summary>
		/// <param name="associated_sub_var"></param>
		/// <param name="name_id"></param>
		private static void AssociatedSubVarRecursion(List<string> associated_sub_var, string name_id)
		{
			for (int i = 0; i < _expToVar[name_id].Count; i++)
			{
				if (!associated_sub_var.Contains(_expToVar[name_id][i]))
				{
					associated_sub_var.Add(_expToVar[name_id][i]);
				}
				if (_expToVar.ContainsKey(_expToVar[name_id][i]))
				{
					AssociatedSubVarRecursion(associated_sub_var, _expToVar[name_id][i]);
				}
			}
		}
	}
}
